import React, {createContext, useState} from 'react';

import journalSpec from './journal';
import universalSpec from './universal-ledger';

// import {
//   uniformedCategory as uniformedCategorySpec,
//   uniformedCategoryAssign as uniformedCategoryAssignSpec
// } from './uniformed-category';


import {
  priorityListSpec,
  cashflowTableSpec,
  cashflowMainSpec,
  cashflowAdditionalSpec
} from './cashflow';

export const LedgerContext = createContext({
  books: [],
  evalBook: () => {},
  currBook: {},
  getBook:() => {},
  addBook:() => {},
  switchBook:() => {},
})

export const LedgerProvider = ({children}) => {

  const [books, setBooks] = useState([
    journalSpec,
    universalSpec,
    priorityListSpec,

    cashflowTableSpec,
    cashflowMainSpec,
    cashflowAdditionalSpec,
  ]);
  const [currBook, setCurrBook] = useState(journalSpec);
  
  const getBook = (bookName) => {
    return books.find(({name}) => name === bookName);
  }

  const addBook = (newBooks) => {

    if (Array.isArray(newBooks)) {
      const reallyNewBooks = [];
      for (let {name, ...rest} of newBooks) {
        const anyExisting = getBook(name);
        if (anyExisting !== undefined)  {
          Object.assign(anyExisting, rest);
        } else {
          reallyNewBooks.push({name, ...rest});
        }
        setBooks([...books, ...reallyNewBooks]);
      }
    } else {
      const {name} = newBooks;
      const anyExisting = getBook(name);
      if (anyExisting !== undefined) {
        Object.assign(anyExisting, newBooks);
        setBooks([...books]);
      } else {
        setBooks([...books, newBooks]);
      }  
    }
  }

  const switchBook = ({name}) => {
    const nextBook = getBook(name);
    if (nextBook === undefined) {
      throw Error('Switching to non-existing book');
    } else {
      setCurrBook(nextBook);
    }
  }

  const evalBook = (name) => {
    const bookStack = [name];
    while (bookStack.length > 0) {

      const procDefault = () => {
        console.log(`NOP ${name}`);
        return true;
      }
      const {eval:{proc=procDefault, next=[]}={}} = getBook(bookStack.pop()) ?? {};
      
      if (proc(books)) {
        bookStack.push(...next);
      }
    }
  }

  const values = {
    currBook,
    getBook,
    addBook,
    evalBook,
    switchBook,
    books
  }

  return <LedgerContext.Provider value={values}>
    {children}
  </LedgerContext.Provider>
}